module AboutYou
  module SDK
    module Model
      ###
      # This class represents a facet group set model
      ###
      class FacetGroupSet
        # Array of ids of the facet groups in this set
        attr_accessor :ids
        # Array of instances of AboutYou::SDK::Model::FacetGroups
        attr_accessor :groups
        # Array of instances of AboutYou::SDK::Model::Facet
        attr_accessor :facets
        class << self
          # instance of AboutYou::SDK::Model::Facet_Manager::DefaultFacetManager
          attr_accessor :facet_manager
        end

        ###
        # Constructor for the AboutYou::SDK::Model::FacetGroupSet class
        #
        # * *Args* :
        #   - +ids+ -> the ids of the facet groups of this set
        #
        # * *Returns* :
        #   - an instance of AboutYou::SDK::Model::FacetGroupSet
        ###
        def initialize(ids)
          self.facets = {}
          self.groups = {}
          ids.each do |_key, facet_ids|
            fail '\InvalidArgumentException! ids must be an associative array
              of [$groupId => [$facetId,...],..]' unless facet_ids.is_a?(Array)
          end
          self.ids = ids

          self
        end

        ###
        # This method checks whether this set is empty
        #
        # * *Returns* :
        #   - Boolean determining whether this set is empty or not
        ###
        def empty?
          ids.empty?
        end

        ###
        # This method is used for generating facet groups for this set
        #
        # * *Returns* :
        #   - Hash containing pairs of group_id => instance of AboutYou::SDK::Model::FacetGroup
        ###
        def gen_lazy_groups
          groups = {}
          ids.each do |group_id, facet_ids|
            group = AboutYou::SDK::Model::FacetGroup.new(group_id, nil)
            facet_ids.each do |facet_id|
              facet = AboutYou::SDK::Model::Facet.new(
                facet_id,
                nil,
                nil,
                group_id,
                nil
              )
              group.add_facet(facet)
            end
            groups[group_id] = group
          end

          groups
        end

        ###
        # Getter for the facet groups of this set
        #
        # * *Returns* :
        #   - Hash containing pairs of group_id => instance of AboutYou::SDK::Model::FacetGroup
        ###
        def lazy_groups
          return @groups unless @groups.empty?
          gen_lazy_groups
        end

        ###
        # This method fetches the facets of this set
        #
        # * *Returns* :
        #   - Hash containing pairs of group_id => instance of AboutYou::SDK::Model::FacetGroup
        ###
        def fetch
          return unless facets && facets.empty?

          ids.each do |group_id, facet_ids|
            facet = self.class.facet_manager.facet(group_id, facet_ids[0])
            next unless facet
            if @groups[group_id]
              group = @groups[group_id]
            else
              group = AboutYou::SDK::Model::FacetGroup.new(
                group_id,
                facet.group_name
              )
              @groups[group_id] = group
            end
            group.add_facet(facet)
            facets[facet.unique_key] = facet
          end
        end

        ###
        # Getter for the facet groups of this set
        #
        # * *Returns* :
        #   - Hash containing pairs of group_id => instance of AboutYou::SDK::Model::FacetGroup
        ###
        def groups
          fetch if @groups.empty?

          @groups
        end

        ###
        # this method is used for getting a group of this set by a group id
        #
        # * *Returns* :
        #   - +group_id+ -> the group id for which the facet group should be returned
        #
        # * *Returns* :
        #   - Either nil if not found or instance of AboutYou::SDK::Model::FacetGroup
        ###
        def group(group_id)
          return groups[group_id] if groups[group_id]
        end

        ###
        # this method is used for checking whether a group is in this set or not
        #
        # * *Returns* :
        #   - +group_id+ -> the group id used for searching
        #
        # * *Returns* :
        #   - Boolean determining whether this set includes the group_id or not
        ###
        def group?(group_id)
          !ids[group_id].empty?
        end

        ###
        # This method gets a facet by key
        #
        # * *Returns* :
        #   - +key+ -> the facet key used for searching
        #
        # * *Returns* :
        #   - Either nil if not found or instance of AboutYou::SDK::Model::Facet
        ###
        def facet_by_key(key)
          fetch
          facets[key] ? facets[key] : nil
        end

        ###
        # This method gets a facet by given facet if and facet group id
        #
        # * *Returns* :
        #   - +facet_group_id+ -> the facet group id used for searching
        #   - +facet_id+ -> the facet id used for searching
        #
        # * *Returns* :
        #   - Either nil if not found or instance of AboutYou::SDK::Model::Facet
        ###
        def facet(facet_group_id, facet_id)
          fetch if facets.empty?

          return facets[String(facet_group_id) + ':' + String(facet_id)] if
          facets[String(facet_group_id) + ':' + String(facet_id)]
        end

        ###
        # This method is used for creating a unique key for this facet group set
        #
        # * *Returns* :
        #   - a String containing a unique key for this facet group set
        ###
        def unique_key
          ids.sort!
          ids.map { |sub_ids| sub_ids.sort! }

          ids.to_json
        end

        ###
        # This method checks whether this set contains a facet or facet group set
        #
        # * *Args* :
        #   - +facet_compable+ -> Facet compable
        #
        # * *Returns* :
        #   - Either nil if wrong input or Boolean determining whether the compable is found or not
        ###
        def contains(facet_compable)
          return contains_facet_group_set(facet_compable) if
          facet_compable.is_a?(self.class)

          return contains_facet_get_group_interface(facet_compable) if
          facet_compable.is_a? AboutYou::SDK::Model::FacetGetGroupInterface

          false
        end

        ###
        # This method checks whether a facet is in this set or not
        #
        # * *Args* :
        #   - +facet+ -> Facet compable
        #
        # * *Returns* :
        #   - Boolean determining whether this set includes the facet or not
        ###
        def contains_facet_get_group_interface(facet)
          lazy_groups = self.lazy_groups
          id = facet.group_id

          if lazy_groups.key?(id)
            return lazy_groups[id].unique_key == facet.unique_key
          end

          false
        end

        ###
        # This method checks whether a facet group set is in this set or not
        #
        # * *Args* :
        #   - +facet_group_set+ -> Facet compable
        #
        # * *Returns* :
        #   - Boolean determining whether this set includes the facet group set or not
        ###
        def contains_facet_group_set(facet_group_set)
          return true if unique_key == facet_group_set.unique_key

          lazy_groups.each do |id, group|
            return false if
            lazy_groups['id'] || lazy_groups[id].unique_key != group.unique_key
          end

          true
        end

        ###
        # This method merges facet ids in an multi dimensional Array
        #
        # * *Args* :
        #   - +facet_ids_array+ -> Multi-Dimensional-Array containing facet ids
        #
        # * *Returns* :
        #   - Array of facet ids
        ###
        def self.merge_facet_ids(facet_ids_array)
          ids = {}

          facet_ids_array.each do |facet_ids_hash|
            facet_ids_hash.each do |group_id, facet_ids|
              if ids[Integer(group_id)]
                ids[Integer(group_id)] = ids[Integer(group_id)] +
                  facet_ids.uniq
              else
                ids[Integer(group_id)] = facet_ids
              end
            end
          end

          ids
        end

        ###
        # getter for the facet group ids
        #
        # * *Returns* :
        #   - Array of facet group ids
        ###
        def group_ids
          ids.keys
        end
      end
    end
  end
end
